#pragma once

#include <string>
#include <vector>
#include <pthread.h>
#include <cstdio>
#include <functional>
#include "mysocket.hpp"
#include "protocol.hpp"
#include "logmessage.hpp"

class TcpServer
{
    using func_t = std::function<void(int)>;
    std::string _ip;
    uint16_t _port;
    Socket _listensock;
    // func_t _func;
    std::vector<func_t> _funcs;

    struct ThreadData
    {
        int _sock;
        TcpServer *_self;

        ThreadData(int sock, TcpServer *self)
            : _sock(sock), _self(self)
        {
        }
    };

public:
    TcpServer(const std::string &ip, uint16_t port)
        : _ip(ip), _port(port)
    {
        _listensock.Bind(_ip, _port);
        _listensock.Listen();
    }

    void AddService(func_t func)
    {
        _funcs.push_back(func);
    }

    void Excute(int sock)
    {
        for (auto f : _funcs)
        {
            f(sock);
        }
    }

    void Start()
    {
        while (true)
        {
            // 1.获取新链接
            std::string client_ip;
            uint16_t client_port;
            int svcsock = _listensock.Accept(&client_ip, &client_port);
            if (svcsock == -1)
                continue;

            LogMessage(NORMAL, "[%s:%d] join, accept a new link!", client_ip.c_str(), client_port);

            pthread_t tid;
            ThreadData *ptd = new ThreadData(svcsock, this);
            pthread_create(&tid, nullptr, ThreadRoutine, ptd);
        }
    }

    static void *ThreadRoutine(void *args)
    {
        pthread_detach(pthread_self());
        // ThreadData *td = (ThreadData *)args;
        ThreadData *td = static_cast<ThreadData *>(args);
        td->_self->Excute(td->_sock);
        LogMessage(NORMAL, "client quit!");
        close(td->_sock);
        delete td;
    }
};